package com.yuantu.judiciary.serviceimpl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.yuantu.judiciary.common.SysCode;
import com.yuantu.judiciary.common.SysOnOffState;
import com.yuantu.judiciary.dao.IAccountDao;
import com.yuantu.judiciary.dao.IAuthInfoDao;
import com.yuantu.judiciary.dao.IOrganizationDao;
import com.yuantu.judiciary.dao.IUserInfoDao;
import com.yuantu.judiciary.exception.enums.AccountExceptionEnum;
import com.yuantu.judiciary.exception.enums.AuthExceptionEnum;
import com.yuantu.judiciary.exception.enums.OrganizationExceptionEnum;
import com.yuantu.judiciary.exception.enums.UserExceptionEnum;
import com.yuantu.judiciary.model.domain.AccountDO;
import com.yuantu.judiciary.model.domain.AuthInfoDO;
import com.yuantu.judiciary.model.domain.OrganizationDO;
import com.yuantu.judiciary.model.domain.UserInfoDO;
import com.yuantu.judiciary.model.dto.SearchRecordContentDTO;
import com.yuantu.judiciary.model.enums.*;
import com.yuantu.judiciary.model.form.IdentifyAuthForm;
import com.yuantu.judiciary.model.vo.IdentifyAuthResVO;
import com.yuantu.judiciary.service.IApiAliAppletService;
import com.yuantu.judiciary.service.IIdentityAuthService;
import com.yuantu.judiciary.utils.AssertUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.sql.Timestamp;

/**
 * 身份认证管理模块
 *
 * @author syw
 * @since 2023-12-26
 **/
@Service
@RequiredArgsConstructor
public class IdentityAuthServiceImpl implements IIdentityAuthService {

    private static final Gson GSON = new Gson();
    private final IUserInfoDao userInfoDao;
    private final IAccountDao accountDao;
    private final IOrganizationDao organizationDao;
    private final IAuthInfoDao authInfoDao;
    private final IApiAliAppletService aliAppletService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public IdentifyAuthResVO getIdentifyAuthByAliApplet(Long accountId, IdentifyAuthForm form) {
        AccountDO account = accountDao.findByIdAndDeletedFalse(accountId);
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(account), AccountExceptionEnum.ACCOUNT_NOT_EXIST);
        UserInfoDO userInfo = userInfoDao.findByIdAndDeletedFalse(account.getUserId());
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(userInfo), UserExceptionEnum.USER_NOT_EXIST);

        // 保存注册信息
        OrganizationDO organization;
        OrganizationDO existOrg = organizationDao.findByTypeAndIdNumberAndDeletedFalse(OrganizationType.SINGLE, form.getIdNumber());
        if (account.getOrganizationId() == null) {
            AssertUtil.assertTrue(ObjectUtils.isEmpty(existOrg), OrganizationExceptionEnum.ORGANIZATION_EXIST);

            organization = new OrganizationDO();
            organization.setOrganizationSourceId(1L);
            BeanUtils.copyProperties(form, organization);
            organization.setType(OrganizationType.SINGLE);
            organization.setState(SysOnOffState.ON);
            organization.setAuthState(AuthState.TO_VERIFY);
            organizationDao.save(organization);

            account.setUsername(form.getUsername());
            account.setType(UserType.PRIMARY);
            account.setOrganizationId(organization.getId());
            accountDao.save(account);
        } else {
            organization = organizationDao.findByIdAndDeletedFalse(account.getOrganizationId());
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(organization), OrganizationExceptionEnum.ORGANIZATION_NOT_EXIST);
            AssertUtil.assertTrue((ObjectUtils.isEmpty(existOrg) || organization.getId().equals(existOrg.getId())), OrganizationExceptionEnum.ORGANIZATION_EXIST);
            if (OrganizationType.SINGLE.equals(organization.getType())) {
                if (!AuthState.PASS.equals(organization.getAuthState())) {
                    BeanUtils.copyProperties(form, organization);
                    organizationDao.save(organization);

                    account.setUsername(form.getUsername());
                    accountDao.save(account);
                }
            } else {
                organization = new OrganizationDO();
                organization.setOrganizationSourceId(1L);
                BeanUtils.copyProperties(form, organization);
                organization.setType(OrganizationType.SINGLE);
                organization.setState(SysOnOffState.ON);
                organization.setAuthState(AuthState.TO_VERIFY);
                organizationDao.save(organization);

                account = new AccountDO();
                account.setUsername(form.getUsername());
                account.setType(UserType.PRIMARY);
                account.setUserId(userInfo.getId());
                account.setOrganizationId(organization.getId());
                account.setState(SysOnOffState.ON);
                account.setOpenId(IdUtil.fastSimpleUUID());
                accountDao.save(account);
            }
        }

        // 身份认证
        String certifyId = aliAppletService.identificationInit(form.getUsername(), form.getIdNumber());
        AssertUtil.assertTrue(StringUtils.isNotBlank(certifyId), SysCode.ALI_APPLET_API_IDENTIFICATION_INIT_ERROR);
        String url = aliAppletService.identificationCertify(certifyId);
        AssertUtil.assertTrue(StringUtils.isNotBlank(url), SysCode.ALI_APPLET_API_IDENTIFICATION_CERTIFY_ERROR);

        // 删除历史数据，保留最新认证信息
        authInfoDao.deleteByRelativeId(organization.getId(), AuthType.REGISTER, OriginType.ALI_APPLET);
        AuthInfoDO authInfo = new AuthInfoDO();
        SearchRecordContentDTO searchRecord = new SearchRecordContentDTO(form.getUsername(), form.getIdNumber(), form.getPhone());
        String content = JSON.toJSONString(searchRecord);
        authInfo.setRelativeId(organization.getId());
        authInfo.setType(AuthType.REGISTER);
        authInfo.setContent(content);
        authInfo.setOriginType(OriginType.ALI_APPLET);
        authInfo.setCertifyId(certifyId);
        authInfo.setExpiresTime(new Timestamp(System.currentTimeMillis() + 23 * 60 * 60 * 1000));
        authInfoDao.save(authInfo);

        return new IdentifyAuthResVO(certifyId, url);
    }

    @Override
    public Boolean getIdentifyAuthResultByAliApplet(Long accountId) {
        AccountDO account = accountDao.findByIdAndDeletedFalse(accountId);
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(account), AccountExceptionEnum.ACCOUNT_NOT_EXIST);
        OrganizationDO organization = organizationDao.findByIdAndDeletedFalse(account.getOrganizationId());
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(organization), OrganizationExceptionEnum.ORGANIZATION_NOT_EXIST);

        // 获取最新认证记录
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        AuthInfoDO authInfo = authInfoDao.findFirstByRelativeIdAndTypeAndOriginTypeAndExpiresTimeGreaterThanEqualAndDeletedFalseOrderByCreateTimeDesc(
                organization.getId(), AuthType.REGISTER, OriginType.ALI_APPLET, currentTime
        );
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(authInfo), AuthExceptionEnum.AUTH_NOT_EXIST_OR_EXPIRES);
        String certifyId = authInfo.getCertifyId();
        String queryRes = aliAppletService.identificationQuery(certifyId);
        AssertUtil.assertTrue(StringUtils.isNotBlank(queryRes), SysCode.ALI_APPLET_API_IDENTIFICATION_QUERY_ERROR);

        boolean res = false;
        JsonObject object = GSON.fromJson(queryRes, JsonObject.class);
        JsonObject response = object.get("alipay_user_certify_open_query_response").getAsJsonObject();
        if (response != null && "10000".equals(response.get("code").getAsString()) && "T".equals(response.get("passed").getAsString())) {
            res = true;
        }
        authInfo.setResult(queryRes);
        authInfo.setPassed(res);
        authInfo.setAuthorizedTime(currentTime);
        authInfoDao.save(authInfo);

        organization.setAuthState(res ? AuthState.PASS : AuthState.NOT_PASS);
        organizationDao.save(organization);

        return res;
    }

}
